home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
299_01
/
mel.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-12-28
|
42KB
|
1,310 lines
/*
---------------------------------------------------------------------------
filename: mel.c
author: g. m. crews
creation date: 28-Jul-1988
date of last revision: 19-Jul-1989
MEL is a comprehensive metalanguage input/output processor for engineering
analysis programs. its purposes are 1) to save the programmer development time
when providing a user-friendly i/o interface, and 2) to establish a common
protocol for interprogram messaging. these routines can be used by any
analysis program for which a "dictionary" has been defined. see file
"mel.doc" for more information.
note: these functions will normally return 0 if no error was encountered,
else a number (code) reflecting the type of error.
functions contained in this file:
module # name global scope?
-------- ----------------------- -------------
1.0 meli_file yes
1.1 end_of_data_in_file no
1.2 meli yes
1.2.1 compact_str no
1.2.2 get_descrip_type no
1.2.2.1 name_match no
1.2.3 get_param_name no
1.2.4 get_param_values no
1.2.5 get_param_units no
2.0 meli_descrip_type yes
3.0 meli_num_params yes
4.0 meli_param yes
5.0 meli_data yes
6.0 melo_init yes
7.0 melo_data yes
8.0 melo_file yes
8.1 melo yes
8.1.1 write_units_if_any no
---------------------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
/*
---------------------------------------------------------------------------
the following include file declares the dictionary that is to be used for
MEL i/o. note that this file will be unique for every program that uses
this method of i/o. (again, see file "mel.doc" for more information on how
to further customize or modify this file.)
it also contains "public" (global) function prototyping and miscellaneous
data structures.
---------------------------------------------------------------------------
*/
#define MEL_INPUT
#define MEL_OUTPUT
#define MEL_PRIVATE
#define MEL_INIT
#include "mel.h"
/* "private" function prototyping:
(visible only to other routines in this file) */
static int end_of_data_in_file(int);
static void compact_str(void);
static int get_descrip_type(void);
static int name_match(char *, char *, int);
static int get_param_name(void);
static int get_param_values(void);
static int get_param_units(void);
static void write_units_if_any(int);
/* "private" (local external) storage: */
static char descrip_str[MELI_MAX_DESCRIP_STR_LEN+1];
/* temp storage for descriptor string.
(read from file or given by MEL user). */
static char *descrip_str_ptr;
/* current point of interest in above string. it is used by several
routines that "translate" the string into MEL data structure. it points
to the next character needing to be "translated". */
static int curr_descrip_index;
/* what is descriptor's index into meli_descrip[] array? this allows
other local routines to know which parameters to check for. */
static int datum_param_index;
/* where does this parameter's data go in meli_datum? */
/* the following variables are also local and deal with parameter handling: */
static int equals_sign_found_flag;
/* will there be a need to try and read a parameter value? */
static int curr_param_index;
/* what is parameter's index into meli_descrip.param[] array? */
static int param_name_found_flag;
/* as a safety measure, note when a parameter name has been found
for a descriptor (and do not let values without names follow). */
static int left_parenthesis_found_flag;
/* will there be a need to try and read units? */
/*
---------------------------------------------------------------------------
module 1.0
get a descriptor string from a file and put data into structure for easy
access. that is:
read a descriptor from a file into "private" storage (descrip_str).
check for file read errors.
stop reading after semicolon encountered.
put a copy into meli_descriptor_string.
translate this string into MEL data structure (meli_datum).
algorithm synopsis: read characters from input stream until semi-
colon (end-of-descriptor) is encountered, while putting them into
private storage string.
---------------------------------------------------------------------------
*/
int meli_file(
FILE *input_file_handle)
{
static int curr_line_num = 1;
/* assume that reading starts with the first line in a text file
and continues incrementally (one descriptor at a time). thus,
increment this variable everytime a newline character is
encountered. (that a descriptor may span several lines.) */
int i;
/* loop counter. */
int ch;
/* current char from input stream. */
meli_datum.start_line = curr_line_num;
/* save the starting line number for this descriptor. */
/* read from the input stream one character at a time: */
for (i = 0; i < MELI_MAX_DESCRIP_STR_LEN; i++) {
ch = fgetc(input_file_handle);
/* check for a file read error: */
if (ferror(input_file_handle)) {
mel_err.type = mel_read_err;
mel_err.start_line = meli_datum.start_line;
mel_err.end_line = curr_line_num;
strcpy(mel_err.msg, "MEL input file");
return mel_read_err;
};
/* also error if unexpected end of file before semicolon: */
if ((ch == EOF) || (feof(input_file_handle))) {
/* an exception is for the case of EOF right after a semicolon
(not counting any whitespace that might also have been read).
this is called the "end-of-data" error (which really isn't an
error at all, but a means of letting the caller know that no
more descriptors are in the file). */
if (end_of_data_in_file(i)) {
mel_err.type = mel_end_of_data_err;
mel_err.start_line = meli_datum.start_line;
mel_err.end_line = curr_line_num;
strcpy(mel_err.msg, "MEL input file");
return mel_end_of_data_err;
} else {
mel_err.type = mel_end_of_file_err;
mel_err.start_line = meli_datum.start_line;
mel_err.end_line = curr_line_num;
strcpy(mel_err.msg, "Missing semicolon, MEL input file");
return mel_end_of_file_err;
}
};
if (ch == ';') break;
/* break the loop if a semicolon is encountered. */
if (ch == '\n') curr_line_num++;
/* increment line number count for a new line */
/* now add this character to the descriptor string and go get the
next character: */
descrip_str[i] = (char)ch;
}
/* the descriptor has now been successfully read into the descriptor
string. time to tidy-up. */
descrip_str[i++] = (char)ch; /* tack on the semicolon */
descrip_str[i] = '\0';
meli_datum.end_line = curr_line_num;
strcpy(meli_descriptor_string, descrip_str);
/* make copy in case user wants to see it. */
/* lastly, translate it (put data into meli_datum): */
return meli();
}
/*
---------------------------------------------------------------------------
module 1.1
has all the data been read from the MEL input file?
this routine is called when an end of file has been encountered. we must make
sure that the user has not forgotten to append a semicolon on the last
descriptor. thus, it is an error condition if anything except whitespace
has been read since the last semicolon (end-of-descriptor character).
return 1 if only whitespace has been read since last semicolon.
return 0 if other (data) characters have been read since last semicolon.
---------------------------------------------------------------------------
*/
static int end_of_data_in_file(
int str_len)
{
descrip_str[str_len] = '\0';
/* make string out of characters read since last semicolon. */
compact_str(); /* remove whitespace from this string */
if (strlen(descrip_str)) return 0;
else return 1;
/* if anything left over after compact